/*
 * Lenovo Group
 * Copyright (c) 2015-2016 All Rights Reserved.
 * 
 * Project Name:itsm-gateway
 * Create Time: 2016年2月4日 下午10:18:12
 */
package com.lenovo.lmrp.server.itsmgateway.spi;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import com.lenovo.lmrp.api.constant.BizErrorCode;
import com.lenovo.lmrp.api.itsmgateway.IItsmTicket;
import com.lenovo.lmrp.api.model.RestResponse;
import com.lenovo.lmrp.api.model.entity.AttachmentPO;
import com.lenovo.lmrp.api.model.entity.AttachmentPO.AttachmentStatus;
import com.lenovo.lmrp.api.model.entity.AttachmentPO.AttachmentType;
import com.lenovo.lmrp.api.model.entity.ProjectPO;
import com.lenovo.lmrp.api.model.entity.TicketExtensePO;
import com.lenovo.lmrp.api.model.entity.TicketPO;
import com.lenovo.lmrp.api.model.entity.TicketPartsPO;
import com.lenovo.lmrp.api.model.entity.TicketPartsPO.PartsAction;
import com.lenovo.lmrp.api.model.view.AttachmentVO;
import com.lenovo.lmrp.api.model.view.ChangedTicketVO;
import com.lenovo.lmrp.api.model.view.PartsVO;
import com.lenovo.lmrp.api.model.view.TicketVO;
import com.lenovo.lmrp.server.itsmgateway.adapter.AItsmAdapterFactory;
import com.lenovo.lmrp.server.itsmgateway.domain.ticket.AttachmentBO;
import com.lenovo.lmrp.server.itsmgateway.domain.ticket.ITicketRepository;
import com.lenovo.lmrp.server.itsmgateway.domain.ticket.TicketBO;
import com.lenovo.sdc.framework.annotation.RestService;
import com.lenovo.sdc.framework.dao.ADaoFactory;
import com.lenovo.sdc.framework.dao.ICommonDAO;
import com.lenovo.sdc.framework.dao.RecordFilter;
import com.lenovo.sdc.framework.util.CommonUtil;
import com.lenovo.sdc.framework.util.Condition;
import com.lenovo.sdc.framework.util.Condition.OperatorEnum;
import com.lenovo.sdc.framework.util.Condition.RelationEnum;
import com.lenovo.sdc.framework.util.PageData;
import com.lenovo.sdc.framework.util.Tuple;
import com.lenovo.sdc.framework.util.exception.ErrorCode;
import com.lenovo.sdc.framework.util.exception.TraceableException;

/**
 * 
 * @author wujin
 * @version v1.0
 */
@RestService
@Path("/itsm/v1")
@Consumes("application/json;charset-utf-8")
@Produces("application/json;charset-utf-8")
public class ItsmTicketImpl implements IItsmTicket {
    private ITicketRepository ticketRepository;

    @Inject
    public void set(ITicketRepository ticketRepository) {
        this.ticketRepository = ticketRepository;
    }

    @Override
    public RestResponse<TicketVO> getTicket(String itsmCode, String ticketID) {
        try {
            TicketBO bo = ticketRepository.createTicketBOWithExtense(itsmCode, ticketID);
            if (Objects.isNull(bo)) {
                return new RestResponse<TicketVO>(ErrorCode.DB_RECORD_NOTFOUND.getCode(),
                    "not found ticket:" + ticketID, null);
            }
            
            return new RestResponse<TicketVO>(0, "OK", bo.getTicketVO());
        }
        catch (Exception exp) {
            return new RestResponse<TicketVO>(ErrorCode.COMM_ERROR.getCode(), itsmCode + ":" + ticketID, null);
        }
    }
    
    @Override
    public RestResponse<Integer> updateTicket(String itsmcode, String ticketid, String action,
                                              ChangedTicketVO changedTicketVO) {
        try {
            TicketBO bo = ticketRepository.createTicketBOWithExtense(itsmcode, ticketid);
            if (Objects.isNull(bo)) {
                return new RestResponse<Integer>(ErrorCode.DB_RECORD_NOTFOUND.getCode(),
                    "not found ticket:" + ticketid, 500);
            }

            boolean isOK = bo.update(action, changedTicketVO.getReason(), changedTicketVO.getFields());
            bo.store(ticketRepository);

            if (isOK) {
                return new RestResponse<Integer>(0, "OK", 500);
            }
            else
                return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), 
                                "sync ticket info to " + itsmcode + " failed", 
                                500);
        }
        catch (Exception exp) {
            return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), itsmcode + ":" + ticketid, 500);
        }
    }

    @Override
    public RestResponse<String> openTicket(String itsmCode, TicketVO ticket) {
        // need to store inspection ticket, when engineer upload attachment should find ticket first
        Tuple.Triplet<Boolean, String, TicketPO> result = AItsmAdapterFactory.getFactory().getAdapter(itsmCode).createTicket(ticket);
        if (result.getOne()) {
            TicketPO po = result.getThird();
            ticketRepository.storeSyncTicket(itsmCode, po);
            
            return new RestResponse<String>(0, "OK", ticket.getTicketid());
        }
        else
            return new RestResponse<String>(ErrorCode.COMM_ERROR.getCode(), result.getSecond(), "");
    }


    @Override
    public RestResponse<String> createAttachment(String itsmcode, String ticketid, AttachmentVO attachmentVO) {
        try {
            AttachmentBO bo = ticketRepository.createAttachmentBO(itsmcode, ticketid, attachmentVO);
            //bo.attachTicket(ticketid);
            bo.store(ticketRepository);

            return new RestResponse<String>(0, "OK", bo.getID());
        }
        catch (TraceableException exp) {
            return new RestResponse<String>(exp.getErrorCode().getCode(), exp.getMessage(), "");
        }
        catch (Exception exp) {
            return new RestResponse<String>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), "");
        }
    }

    /**
     * update ticket attachment status, file store path and cnd url
     */
    @Override
    public RestResponse<Integer> updateAttachment(String itsmcode, String ticketid, String attachmentid, AttachmentVO attachmentVO) {
        try {
            AttachmentBO bo = ticketRepository.createAttachmentBO(itsmcode, attachmentid);
            bo.attachTicket(ticketid);
            bo.changeStatus(attachmentVO.getSubmitter(), AttachmentStatus.values()[attachmentVO.getStatus()]);
            bo.setPath(attachmentVO.getPath(), attachmentVO.getUrl());
            bo.store(ticketRepository);

            return new RestResponse<Integer>(0, "OK", 0);
        }
        catch (TraceableException exp) {
            return new RestResponse<Integer>(exp.getErrorCode().getCode(), exp.getMessage(), -1);
        }
        catch (Exception exp) {
            return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), -1);
        }
    }

    @Override
    public RestResponse<List<AttachmentVO>> listAttachment(String itsmcode, String ticketid, int status, String types) {
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmcode)) {
            RecordFilter filter = new RecordFilter();
            filter.addCondition(new Condition<String, Object>("ticketid", ticketid));
            
            if (status != -1) {
                filter.addCondition(new Condition<String, Object>("status", AttachmentStatus.values()[status]));
            }
            
            if (CommonUtil.nonNullAndEmpty(types) && ! types.equals("-1")) {
                String[] items = types.split(",");
                AttachmentType[] values = new AttachmentType[items.length];
                for (int i = 0; i < items.length; i++)
                    values[i] = AttachmentType.values()[Integer.parseInt(items[i])];
                
                filter.addCondition(new Condition<String, Object>("type", values, OperatorEnum.IN));
            }
            
            List<AttachmentPO> pos = dao.filteByCondition(AttachmentPO.class, filter);
            List<AttachmentVO> vos = new ArrayList<>(pos.size());
            for (AttachmentPO po : pos) {
                AttachmentVO vo = new AttachmentVO();
                vo.setId(po.getId());
                vo.setName(po.getFileName());
                vo.setStatus(po.getStatus().ordinal());
                vo.setType(po.getType().ordinal());
                vo.setUrl(po.getCdnURL());
                vo.setPath(po.getStorePath());
                vo.setOriginal(po.getOriginalPath());
                vos.add(vo);
            }
            
            return new RestResponse<List<AttachmentVO>>(0, "OK", vos);
        }
        catch (Exception exp) {
            exp.printStackTrace();
            return new RestResponse<List<AttachmentVO>>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), null);
        }
    }

    /**
     * When attachment has uploaded to platform, for some reason file wasn't
     * sync to ITSM, invoke this method to sync file to ITSM.
     */
    @Override
    public RestResponse<Integer> syncAttachment(String itsmCode, String ticketid) {
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
            RecordFilter filter = new RecordFilter();
            filter.addCondition(new Condition<String, Object>("status", new Object[]{AttachmentStatus.UPLOADED}));
            filter.addCondition(new Condition<String, Object>("ticketid", ticketid));
            List<AttachmentPO> attachs = dao.filteByCondition(AttachmentPO.class, filter);
            if (attachs.size() > 0) {
                // should use thread pool!!!
                new Thread() {
                    public void run() {
                        for (AttachmentPO po : attachs) {
                            try {
                                AttachmentBO bo = ticketRepository.createAttachmentBO(itsmCode, po);
                                bo.syncAttachment();
                                bo.store(ticketRepository);
                            }
                            catch (Exception exp) {
                                continue;
                            }
                        }
                    }
                }.start();
            }
            
            return new RestResponse<Integer>(0, "OK", attachs.size());
        }
        catch (Exception exp) {
            return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), -1);
        }
    }

    @Override
    public RestResponse<AttachmentVO> getAttachment(String itsmCode, String ticketid, String attachmentid) {
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
            AttachmentPO po = dao.get(AttachmentPO.class, attachmentid);
            if(Objects.isNull(po))
                return new RestResponse<AttachmentVO>(0, "OK", null);
            else {
                AttachmentVO vo = new AttachmentVO();
                vo.setId(po.getId());
                vo.setName(po.getFileName());
                vo.setStatus(po.getStatus().ordinal());
                vo.setPath(po.getStorePath());
                vo.setUrl(po.getCdnURL());
                return new RestResponse<AttachmentVO>(0, "OK", vo);
            }
        }
        catch (Exception exp) {
            return new RestResponse<AttachmentVO>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), null);
        }
    }

    @Override
    public RestResponse<PartsVO> getParts(String itsmCode, String ticketid, String partnum) {
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
            TicketPartsPO po = dao.get(TicketPartsPO.class, partnum);
            if(Objects.isNull(po))
                return new RestResponse<PartsVO>(ErrorCode.DB_RECORD_NOTFOUND.getCode(), "OK", null);
            else {
                PartsVO vo = new PartsVO();
                vo.setPartsnum(po.getId());
                vo.setPartsname(po.getName());
                vo.setFru(po.getFRU());
                vo.setDescription(po.getDescription());
                vo.setNew(po.getType().equals(PartsAction.UP) ? true : false);
                return new RestResponse<PartsVO>(0, "OK", vo);
            }
        }
        catch (Exception exp) {
            return new RestResponse<PartsVO>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), null);
        }
    }

    @Override
    public RestResponse<List<PartsVO>> listParts(String itsmCode, String ticketid) {
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
            RecordFilter filter = new RecordFilter();
            filter.addCondition(new Condition<String, Object>("ticketid", ticketid));
            List<TicketPartsPO> pos = dao.filteByCondition(TicketPartsPO.class, filter);
            
            List<PartsVO> vos = new ArrayList<>(pos.size());
            for(Iterator<TicketPartsPO> it = pos.iterator(); it.hasNext();) {
                TicketPartsPO po = it.next();
                PartsVO vo = new PartsVO();
                vo.setPartsnum(po.getId());
                vo.setPartsname(po.getName());
                vo.setFru(po.getFRU());
                vo.setNew(po.getType().equals(PartsAction.UP) ? true : false);
                vos.add(vo);
                
                it.remove();
            }
            
            return new RestResponse<List<PartsVO>>(0, "OK", vos);
        }
        catch (Exception exp) {
            return new RestResponse<List<PartsVO>>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), null);
        }
    }
    
    @Override
    public RestResponse<Integer> replaceParts(String itsmcode, String ticketid, List<PartsVO> partsList) {
        try {
            TicketBO bo = ticketRepository.createTicketBO(itsmcode, ticketid);
            if (Objects.isNull(bo)) {
                return new RestResponse<Integer>(ErrorCode.DB_RECORD_NOTFOUND.getCode(),
                    "not found ticket:" + ticketid, 
                    500);
            }

            // TODO, currently we haven't status field to indicate record whether synced to ITSM successfully!!!
            Tuple.Pair<Boolean, String> result = bo.addParts(partsList);
            bo.store(ticketRepository);
            if (result.getOne()) {
                return new RestResponse<Integer>(0, "OK", 500);
            }
            else
                return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), 
                                "sync parts to " + itsmcode + " failed:" + result.getSecond(), 
                                500);
        }
        catch (Exception exp) {
            return new RestResponse<Integer>(ErrorCode.COMM_ERROR.getCode(), itsmcode + ":" + ticketid, 500);
        }
    }

	@Override
	public RestResponse<PageData<TicketPO>> listTicket(String itsmCode, String id, String projectName, String status,
			int page, int rows) {
		// TODO Auto-generated method stub
        try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
            RecordFilter filter = new RecordFilter();
            if (CommonUtil.nonNullAndEmpty(id)) {
                filter.addCondition(new Condition<String, Object>("id", id, OperatorEnum.LIKE));
            }
            if (CommonUtil.nonNullAndEmpty(projectName)) {
                filter.addCondition(new Condition<String, Object>("caption", projectName, OperatorEnum.LIKE), RelationEnum.AND);
            }
            if (CommonUtil.nonNullAndEmpty(status)) {
                String[] split = status.split(",");
                Object[] statuss = new Object[split.length];
                for (int i = 0; i < statuss.length; i++) {
                    statuss[i] = Integer.parseInt(split[i]);
                }
                filter.addCondition(new Condition<String, Object>("status", statuss, OperatorEnum.IN), RelationEnum.AND);
            }

            PageData<TicketPO> pageData = null;
            pageData = new PageData<>(page, rows, true);
            dao.filteByCondition(TicketPO.class, filter, pageData);
            
            return new RestResponse<PageData<TicketPO>>(0, "OK", pageData);
        }
        catch (Exception exp) {
            TraceableException.writeLog(ErrorCode.DB_QUERY_FAILED, "query project", exp);
            return new RestResponse<PageData<TicketPO>>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), null);
        }
	}

	/* (non-Javadoc)
	 * @see com.lenovo.lmrp.api.itsmgateway.IItsmTicket#updateTicketExtense(java.lang.String, java.lang.String, java.util.Map)
	 */
	@Override
	public RestResponse<Integer> updateTicketExtense(String itsmcode, String ticketid, Map<String, Object> extense) {
		
		try {
			TicketBO ticketBO = ticketRepository.createTicketBOWithExtense(itsmcode, ticketid);
			ticketBO.updateTicketExtense(ticketRepository, extense);
		} catch (Exception exp) {
			TraceableException.writeLog(BizErrorCode.ITSMGW_DB_ERROR, "update ticket extense failed", exp);
			return new RestResponse<Integer>(1, "db error", 0);
		}
		return new RestResponse<Integer>(1);
	}
	
	@Override
	public RestResponse<TicketPO> getTicketExt(String itsmCode, String ticketid) {
		// TODO Auto-generated method stub
		 try (ICommonDAO dao = ADaoFactory.getDefault().createDAO(itsmCode)) {
	            TicketPO ticket = dao.get(TicketPO.class, ticketid);
	            ticket.setOthers(dao.get(TicketExtensePO.class, ticketid));
	            return new RestResponse<TicketPO>(ticket);
	        }
	        catch (Exception exp) {
	            TraceableException.writeLog(ErrorCode.DB_QUERY_FAILED, "query ticket", exp);
	            return new RestResponse<TicketPO>(ErrorCode.COMM_ERROR.getCode(), exp.getMessage(), null);
	        }
	}
}
